package values;
import be.kuleuven.cs.som.annotate.*;
/**
 * A class representing twodimensional vectors. 
 * Vectors have two components. One in the direction of the x axis and one in the direction of the y axis.
 * 
 * @invar	isValidComponent(getxComp())
 * @invar	isValidComponent(getyComp())
 *  
 * @version 1.2
 * @author JeroenGillis && ThomasProvoost
 *
 */
@Value
public class Vector {
	private final double xComp;
	private final double yComp;
	
	/**
	 * Create a new vector based upon two euclidian coordinates.
	 * @param 	xComp
	 * 			X coordinate of this new vector.
	 * @param 	yComp
	 * 			Y coordinate of this new vector.
	 * @post	If the given xComp is valid, this new vector has an xComp equal to the given xComp.
	 * 			| new.getxComp() == xComp
	 * @post	If the given yComp is valid, this new vector has an yComp equal to the given yComp.
	 * 			| new.getyComp() == yComp
	 */
	public Vector(double xComp, double yComp) {
		if(isValidComponent(xComp) != true) xComp = 0;
		this.xComp = xComp;
		
		if(isValidComponent(yComp) != true) yComp = 0;
		this.yComp = yComp;
	}
	
	/**
	 * Create a new vector based upon a length and an angle
	 * @param 	length
	 * 			The length of this new vector.
	 * 			| (new this).getLength() == length
	 * @param 	angle
	 * 			The angle of this new vector.
	 * 			| (new this).getAngle() == angle
	 * @param 	polar
	 * 			A boolean reflecting this vector uses polar arguments.
	 */
	public Vector(double length, double angle, boolean polar) {
		this(length*Math.cos(angle),length*Math.sin(angle));
	}
	
	/**
	 * Return the final x component of this vector.
	 */
	@Basic @Immutable
	public double getxComp() {
		return xComp;
	}
	
	/**
	 * Return the final y component of this vector.
	 */
	@Basic @Immutable
	public double getyComp() {
		return yComp;
	}
	
	/**
	 * Return a boolean reflecting whether this vector can have the given value as a component.
	 * @param	comp
	 * 			The component to be checked.
	 * @return	False if and only if the given component is not a number,
	 * 			else true.
	 * 			| if (comp == Double.NaN) result == false
				|	else result == true
	 */
	public boolean isValidComponent(double comp) {
		if (Double.isNaN(comp)) return false;
		else return true;
	}
	 
	/**
	 * Return the length of this vector
	 * @return	Return the length of this vector. 
	 * 			| result == Math.sqrt(Math.pow(getxComp(),2)+Math.pow(getyComp(),2))
	 */
	@Immutable
	public double getLength() {
		return Math.sqrt(Math.pow(getxComp(),2)+Math.pow(getyComp(),2));
	}
	
	/**
	 * Return a new vector which is the sum of this vector and the given otherVector.
	 * @param	otherVector
	 * 			The vector added to this vector
	 * @return	A new vector which is the sum of this vector and the given otherVector.
	 * 			| result == new Vector(this.getxComp() + otherVector.getxComp(),this.getyComp() + otherVector.getyComp());
	 */
	public Vector add(Vector otherVector) {
		return new Vector(this.getxComp() + otherVector.getxComp(),this.getyComp() + otherVector.getyComp());
	}
	
	/**
	 * Return a new vector which is the product of this vector and the given scalar. 
	 * The components of this vector are multiplied by the given double scalar.
	 * @param	scalar
	 * @return	A new vector which is the product of this vector and the given scalar.
	 * 			| result == new Vector(this.getxComp()*scalar,this.getyComp()*scalar)
	 */
	public Vector multiplyScalar(double scalar) {
		return new Vector(this.getxComp()*scalar,this.getyComp()*scalar);
	}
	
	/**
	 * Return a new vector which components are the subtraction of this vectors components and the given otherVectors components.
	 * @param	otherVector
	 * 			The other vector.
	 * @return	result == this.add(otherVector.multiplyScalar(-1))
	 */
	public Vector subtract(Vector otherVector) {
		return add(otherVector.multiplyScalar(-1));
	}
	
	/**
	 * Return a double which is the scalarproduct between this vector and the given other vector.
	 * @param	otherVector
	 * 			The other vector.
	 * @return	A double which is the scalarproduct between this vector and the given other vector.
	 * 			| result == this.getxComp()*otherVector.getxComp() + this.getyComp()*otherVector.getyComp()
	 */
	public double scalarProduct(Vector otherVector) {
		return this.getxComp()*otherVector.getxComp() + this.getyComp()*otherVector.getyComp();
	}
	
	/**
	 * Return a vector with the same angle as this vector and a length 1.
	 * @return	A normalized version of this vector
	 * 			| result == new Vector(1,getAngle(),true)
	 */
	@Immutable
	public Vector normalize() {
		return new Vector(1,getAngle(),true);
	}
	
	/**
	 * Return the angle between this vector and the positive x axis.
	 * @return	The angle of this vector
	 * 			| if(isInfinite()) result == 0.0
	 * 			| else result == Math.atan2(getyComp(),getxComp())
	 */
	@Immutable
	public double getAngle() {
		if(isInfinite()) 
			return 0.0;
		else
			return Math.atan2(getyComp(),getxComp());
	}
	
	/**
	 * Return a boolean reflecting whether this vector is infinite or not.
	 * @return	True if one of the components of this vector is positive or negative infinity.
	 * 			False if not.
	 * 			| if( getxComp() == Double.NEGATIVE_INFINITY || getxComp() == Double.POSITIVE_INFINITY ||
	 *			|		getyComp() == Double.NEGATIVE_INFINITY || getyComp() == Double.POSITIVE_INFINITY) 	result == true
	 *			| else 		result == true
	 */
	@Immutable
	public boolean isInfinite() {
		if(getxComp() == Double.NEGATIVE_INFINITY || getxComp() == Double.POSITIVE_INFINITY ||
				getyComp() == Double.NEGATIVE_INFINITY || getyComp() == Double.POSITIVE_INFINITY) return true;
		else return false;
	}
	
	/**
	 * Return a boolean reflecting whether this vector's length is smaller than the given value. 
	 * @param	length
	 * 			The length to be checked.
	 * @return	...
	 * 			| result == (this.getLength() < length)
	 */
	public boolean isSmallerThan(double length) {
		return this.getLength() <= length;
	}
	
	/**
	 * Return a boolean reflecting whether this vector has the same components as the given vector.
	 */
	@Override
	public boolean equals(Object other) {
		if (other == null)
			return false;
		if (this.getClass() != other.getClass())
			return false;
		Vector otherVector = (Vector) other;
		return (this.getxComp() == otherVector.getxComp() && this.getyComp() == otherVector.getyComp());
	}
	
}
